/*
 * Copyright (C) 2012-2016 TeraCN
 * 
 * This file is part of TeraCN.
 * 
 * TeraCN is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * TeraCN is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package tera.gameserver.network.serverpackets;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import tera.gameserver.manager.DataBaseManager;
import tera.gameserver.model.equipment.Equipment;
import tera.gameserver.model.equipment.SlotType;
import tera.gameserver.model.playable.PlayerAppearance;
import tera.gameserver.model.playable.PlayerPreview;
import tera.gameserver.model.playable.Playerdetails2;
import tera.gameserver.network.ServerPacketType;

import rlib.util.Strings;
import rlib.util.array.Array;
import rlib.util.array.Arrays;

/**
 * @author Ronn Mod Evestu
 */
public class PlayerList extends ServerPacket
{
	
	/**
	 * 0x5622 [0] AD012256 01002700 00000000 00000000 .."V..'......... [16] 00090000 00010000 00000005 00000000 ................ [32] 00000048 00000027 00000000 0000003B ...H...'.......; [48] 014D0120 006D0140 0047B340 00010000 .M. .m.@.G.@.... [64] 00040000 00070000 00010000 00A08601
	 * ................ [80] 00A08601 00000000 00000000 00000000 ................ [96] 007F7000 00000000 00007F70 00000000 .p.......p.... [112] 000098C6 C2A81827 00000000 00000000 .......'........ [128] 00009F3A 0000A03A 0000A13A 00000000 ...:...:...:.... [144] 00000000 00000000 00000000 00000000
	 * ................ [160] 00006505 0A000A1A 04000000 00000000 ..e............. [176] 00000000 00000000 1956C2A8 00000000 .........V...... [192] 00000000 00000000 00000000 00000000 ................ [208] 00000000 00000000 00000000 00000000 ................ [224] 00000000 00000000 00000000
	 * 00000000 ................ [240] 00000000 00000000 00000000 00000000 ................ [256] 00000000 00000000 00000000 00000000 ................ [272] 00000000 00000000 00000000 00000000 ................ [288] 00000000 00000000 A3010000 01010000 ................ [304] 00000164 00000000
	 * 0000006E 00720078 ...d.......n.r.x [320] 00710071 00310032 00330000 000C0C10 .q.q.1.2.3...... [336] 15000000 00171413 00131A05 0010000C ................ [352] 0D000000 06151710 0C17100E 09011310 ................ [368] 13131013 13130F0F 0F0F0F0F 0F10130A ................ [384] 00050B10
	 * 00000000 00000000 00000000 ................ [400] 00000000 00000000 00000000 00000000 ................ [416] 00000000 00000000 00000000 00 ............
	 */
	private static final ServerPacket instance = new PlayerList();
	
	/**
	 * Method getInstance.
	 * @param accountName String
	 * @return PlayerList
	 */
	public static PlayerList getInstance(String accountName)
	{
		final PlayerList packet = (PlayerList) instance.newInstance();
		final ByteBuffer buffer = packet.getPrepare();
		final DataBaseManager dbManager = DataBaseManager.getInstance();
		final Array<PlayerPreview> playerList = packet.getPlayerList();
		dbManager.restorePlayerList(playerList, accountName);
		final int size = playerList.size();
		int sizeTo = 0;
		// packet.writeInt(buffer, 0x562201AD);
		packet.writeShort(buffer, size); // 角色个数 2
		
		if (size > 0)
		{
			packet.writeShort(buffer, 39); // 4
			packet.writeLong(buffer, 0); // 12
			
			// 第二行 16
			packet.writeByte(buffer, 0); // 0x00
			packet.writeInt(buffer, 9); // 0x00090000 00
			packet.writeInt(buffer, 1); // 0x00090000 00010000 00
			packet.writeShort(buffer, 0); // 00090000 00010000 000000
			packet.writeInt(buffer, 5);// 00090000 00010000 00000005 000000
			packet.writeByte(buffer, 0);// 00090000 00010000 00000005 00000000 28
			
			packet.writeShort(buffer, 0);
			packet.writeShort(buffer, 0x4800);
			packet.writeShort(buffer, 0);
			packet.writeByte(buffer, 0); // 35
			final PlayerPreview[] array = playerList.array();
			final PlayerPreview last = playerList.last();
			
			for (int i = 0; i < size; i++)
			{
				
				sizeTo = buffer.position() + 4;
				packet.writeShort(buffer, sizeTo); // 写入前面的字节数
				final PlayerPreview current = array[i];
				
				// 写入下一个角色开始的位置
				if (current == last)
				{
					packet.writeShort(buffer, 0);
				}
				else
				{
					packet.writeShort(buffer, sizeTo + 372 + Strings.length(current.getName()));
				}
				
				packet.writeInt(buffer, 0);
				packet.writeShort(buffer, sizeTo += 276); // sizeTo =315
				packet.writeShort(buffer, sizeTo + Strings.length(current.getName()));
				packet.writeShort(buffer, 32);
				packet.writeShort(buffer, sizeTo + 32 + Strings.length(current.getName()));
				packet.writeShort(buffer, 64);
				packet.writeInt(buffer, current.getObjectId());
				packet.writeInt(buffer, current.getSex());
				packet.writeInt(buffer, current.getRaceId());
				packet.writeInt(buffer, current.getClassId());
				packet.writeInt(buffer, current.getLevel());
				packet.writeInt(buffer, 0x000186A0);
				packet.writeInt(buffer, 0x000186A0);
				packet.writeInt(buffer, 0);
				packet.writeInt(buffer, 0);
				packet.writeInt(buffer, 0);
				packet.writeInt(buffer, 0x0000707F);
				packet.writeInt(buffer, 0);
				packet.writeByte(buffer, 0);
				packet.writeInt(buffer, 0x0000707F);
				packet.writeInt(buffer, 0);
				packet.writeInt(buffer, 0xA8BFFA9D);
				final Equipment equipment = current.getEquipment();
				
				packet.writeInt(buffer, equipment.getItemId(SlotType.SLOT_WEAPON)); // 武器
				packet.writeInt(buffer, 0);
				packet.writeInt(buffer, 0);
				packet.writeInt(buffer, equipment.getItemId(SlotType.SLOT_ARMOR)); // 装甲
				packet.writeInt(buffer, equipment.getItemId(SlotType.SLOT_GLOVES)); // 手套
				packet.writeInt(buffer, equipment.getItemId(SlotType.SLOT_BOOTS)); // 靴子
				packet.writeInt(buffer, 0);
				packet.writeInt(buffer, 0);
				packet.writeInt(buffer, 0);
				// packet.writeInt(buffer, 0);
				packet.writeInt(buffer, equipment.getItemId(SlotType.SLOT_HAT)); // 帽子
				packet.writeInt(buffer, equipment.getItemId(SlotType.SLOT_MASK)); // 面具
				// packet.writeInt(buffer, 0);
				final PlayerAppearance appearance = current.getAppearance();
				final Playerdetails2 detailsappearance = current.getdetails2();
				packet.writeByte(buffer, 65);
				packet.writeByte(buffer, appearance.getFaceColor());
				packet.writeByte(buffer, appearance.getFaceSkin());
				packet.writeByte(buffer, appearance.getAdormentsSkin());
				packet.writeByte(buffer, appearance.getFeaturesSkin());
				packet.writeByte(buffer, appearance.getFeaturesColor());
				packet.writeByte(buffer, appearance.getVoice());
				packet.writeByte(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeInt(buffer, 0);
				packet.writeShort(buffer, 0);
				packet.writeInt(buffer, 0xA8BF8A1E);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeLong(buffer, 0);
				packet.writeInt(buffer, 0);
				packet.writeInt(buffer, 0x000001A3);
				// packet.writeInt(buffer, 0x000001A3);
				packet.writeByte(buffer, 1);
				
				if (current.getOnlineTime() > 15000)
				{
					packet.writeByte(buffer, 0);
				}
				else
				{
					packet.writeByte(buffer, 1);
				}
				
				packet.writeInt(buffer, 0);
				packet.writeByte(buffer, 1);
				packet.writeInt(buffer, 0x00000064);
				packet.writeInt(buffer, 0);
				packet.writeString(buffer, current.getName());
				packet.writeByte(buffer, appearance.getBoneStructureBrow());
				packet.writeByte(buffer, appearance.getBoneStructureCheekbones());
				packet.writeByte(buffer, appearance.getBoneStructureJaw());
				packet.writeByte(buffer, appearance.getBoneStructureJawJut());
				packet.writeByte(buffer, appearance.getEarsRotation());
				packet.writeByte(buffer, appearance.getEarsExtension());
				packet.writeByte(buffer, appearance.getEarsTrim());
				packet.writeByte(buffer, appearance.getEarsSize());
				packet.writeByte(buffer, appearance.getEyesWidth());
				packet.writeByte(buffer, appearance.getEyesHeight());
				packet.writeByte(buffer, appearance.getEyesSeparation());
				packet.writeByte(buffer, 0);
				packet.writeByte(buffer, appearance.getEyesAngle());
				packet.writeByte(buffer, appearance.getEyesInnerBrow());
				packet.writeByte(buffer, appearance.getEyesOuterBrow());
				packet.writeByte(buffer, 0);
				packet.writeByte(buffer, appearance.getNoseExtension());
				packet.writeByte(buffer, appearance.getNoseSize());
				packet.writeByte(buffer, appearance.getNoseBridge());
				packet.writeByte(buffer, appearance.getNoseNostrilWidth());
				packet.writeByte(buffer, appearance.getNoseTipWidth());
				packet.writeByte(buffer, appearance.getNoseTip());
				packet.writeByte(buffer, appearance.getNoseNostrilFlare());
				packet.writeByte(buffer, appearance.getMouthPucker());
				packet.writeByte(buffer, appearance.getMouthPosition());
				packet.writeByte(buffer, appearance.getMouthWidth());
				packet.writeByte(buffer, appearance.getMouthLipThickness());
				packet.writeByte(buffer, appearance.getMouthCorners());
				packet.writeByte(buffer, appearance.getEyesShape());
				packet.writeByte(buffer, appearance.getNoseBend());
				packet.writeByte(buffer, appearance.getBoneStructureJawWidth());
				packet.writeByte(buffer, appearance.getMothGape());
				final int[] jp = detailsappearance.getDetails2();
				
				for (int r = 0; r < 64; ++r)
				{
					packet.writeByte(buffer, jp[r]);
				}
			}
			
			for (int i = 0; i < size; i++)
			{
				array[i].fold();
			}
		}
		else
		{
			packet.writeShort(buffer, 0);
			packet.writeInt(buffer, 0);
			packet.writeInt(buffer, 0);
			packet.writeByte(buffer, 0);
			packet.writeInt(buffer, 2);
			packet.writeInt(buffer, 1);
			packet.writeShort(buffer, 0);
			packet.writeInt(buffer, 40);
			packet.writeInt(buffer, 0);
			packet.writeInt(buffer, 24);
		}
		
		return packet;
	}
	
	private final Array<PlayerPreview> playerList;
	
	private final ByteBuffer prepare;
	
	public PlayerList()
	{
		playerList = Arrays.toArray(PlayerPreview.class);
		prepare = ByteBuffer.allocate(4096).order(ByteOrder.LITTLE_ENDIAN);
	}
	
	/**
	 * Method finalyze.
	 * @see rlib.util.pools.Foldable#finalyze()
	 */
	@Override
	public void finalyze()
	{
		playerList.clear();
		prepare.clear();
	}
	
	/**
	 * Method getPacketType.
	 * @return ServerPacketType
	 */
	@Override
	public ServerPacketType getPacketType()
	{
		return ServerPacketType.S_GET_USER_LIST;
	}
	
	/**
	 * Method getPlayerList.
	 * @return Array<PlayerPreview>
	 */
	public Array<PlayerPreview> getPlayerList()
	{
		return playerList;
	}
	
	/**
	 * Method getPrepare.
	 * @return ByteBuffer
	 */
	public ByteBuffer getPrepare()
	{
		return prepare;
	}
	
	/**
	 * Method isSynchronized.
	 * @return boolean
	 * @see rlib.network.packets.SendablePacket#isSynchronized()
	 */
	@Override
	public boolean isSynchronized()
	{
		return false;
	}
	
	/**
	 * Method writeImpl.
	 * @param buffer ByteBuffer
	 */
	@Override
	protected void writeImpl(ByteBuffer buffer)
	{
		writeOpcode(buffer);
		prepare.flip();
		// System.out.println("player list:\n" + Util.hexdump(prepare.array(), prepare.limit()));
		buffer.put(prepare);
	}
}